#include "stdafx.h"
#include "../vfs/VirtualLocation.h"
#include "../vfs/VirtualProfile.h"
#include "../vfs/PathFwd.h"
#include "../vfs/ILocation.h"
#include "../vfs/IDirectory.h"
#include "../vfs/VirtualFileSystem.h"

namespace ja2{ namespace vfs
{
	VirtualFileSystem *VirtualFileSystem::instance()
	{
		static VirtualFileSystem *p_instance = nullptr;
		if(p_instance == nullptr)
			p_instance = new VirtualFileSystem();

		return p_instance;
	}

	bool VirtualFileSystem::file_exists(boost::filesystem::path const &FilePath) const
	{
		boost::filesystem::path const upper_path(boost::algorithm::to_upper_copy(FilePath.string()));
		// Location exist
		if(virtual_location_exist(upper_path.parent_path()))
		{
			// Get the location
			VirtualLocation* p_virt_loc = get_virtual_location(upper_path.parent_path());
			// File exist
			return p_virt_loc->file_exist(upper_path.filename());
		}
		
		return false;
	}

	bool VirtualFileSystem::file_exists(boost::filesystem::path const &/*FilePath*/, std::string const &/*ProfileName*/) const
	{
/*
		// Virtual location exist, find there
		if(virtual_location_exist(FilePath.parent_path()))
			return get_virtual_location(FilePath.parent_path())->file_exist(FilePath.filename());
*/
		return false;
	}

	FileProxy VirtualFileSystem::open_file(boost::filesystem::path const &/*FilePath*/, std::string const &/*ProfileName*/) const
	{
		// Try to find location
//		return m_LocationMap.find(FilePath.parent_path())->second->get_file(FilePath.filename(), ProfileName);
		return FileProxy();
	}

	FileProxy VirtualFileSystem::open_file(boost::filesystem::path const &FilePath) const
	{
		boost::filesystem::path const upper_path(boost::algorithm::to_upper_copy(FilePath.string()));
		// Get the location first
		return get_virtual_location(upper_path.parent_path())->get_file(upper_path.filename());
	}

	VirtualLocation *VirtualFileSystem::get_virtual_location(boost::filesystem::path const &Path) const
	{
		return m_LocationMap.find(Path)->second.get();
	}

	void VirtualFileSystem::create_virtual_location(boost::filesystem::path const &Path, bool IsExclusive)
	{
		JA2_ASSERT(!virtual_location_exist(Path));
		// Add to map
		m_LocationMap[Path] = VirtualLocationPtr_t(new VirtualLocation(Path, IsExclusive));
	}

	VirtualLocation *VirtualFileSystem::get_create_virtual_location(boost::filesystem::path const &Path, bool IsExclusive)
	{
		// Doesn't exist
		if(!virtual_location_exist(Path))
			create_virtual_location(Path, IsExclusive);
		
		return get_virtual_location(Path);
	}

	bool VirtualFileSystem::virtual_location_exist(boost::filesystem::path const &Path) const
	{
		return (m_LocationMap.count(Path) == 1);
	}

	bool VirtualFileSystem::profile_exists(std::string const &Profile) const
	{
		return (m_ProfileMap.count(Profile) == 1);
	}

	void VirtualFileSystem::add_location(ILocationPtr_t &&pLocation, std::string const &ProfileName, bool IsWritable)
	{
		VirtualProfile *p_profile = nullptr;
		// Profile not found, create one
		if(!profile_exists(ProfileName))
		{
			p_profile = new VirtualProfile(ProfileName, IsWritable);
			m_ProfileMap[ProfileName] = VirtualProfilePtr_t(p_profile);
		}
		else
			p_profile = get_profile(ProfileName);
		// Create virtual location for all sub-dirs	
		for(auto it = pLocation->begin(), end = pLocation->end(); it != end; ++it)
		{
			boost::filesystem::path const location_path = (*it)->get_path();
			// Create virtual location if doesn't exist
			auto p_virtual_location = get_create_virtual_location(location_path, IsWritable);
			// Add all files of location
			for(auto it_files = (*it)->begin(), end_files = (*it)->end(); it_files != end_files; ++it_files)
			{
				FileProxy file(*it_files);
				// Add file to virtual location
				p_virtual_location->add_file(file);
			}
		}
		// Add location to profile
		p_profile->add_location(std::move(pLocation));
	}

	VirtualProfile *VirtualFileSystem::create_profile(std::string const &Name, bool Writeable)
	{
		VirtualProfile *p_profile = new VirtualProfile(Name, Writeable);
		m_ProfileMap[Name] = VirtualProfilePtr_t(p_profile);

		return p_profile;
	}

	VirtualProfile *VirtualFileSystem::get_profile(std::string const &Name) const
	{
		assert(profile_exists(Name));
		return m_ProfileMap.find(Name)->second.get();
	}
} /*ja2*/} /*vfs*/
